 #include <QtGui>
#include <QPainter>
#include <algorithm>
#include <iostream>
using namespace std;

 #include "diagramitem.h"
#include "edge.h"
#include "scene.h"

 DiagramItem::DiagramItem(DiagramType diagramType,
              QGraphicsItem *parent, QGraphicsScene *scene)
     : QGraphicsPolygonItem(parent, scene)
 {
	QPolygonF myPolygon;
	myDiagramType = diagramType;
	//line = false;
	per = 0.5;
	filtered = false;
    myId = "di" + QString::number(rand());

        if ( myDiagramType < 4)
        { width= 40; height = 30;}
        else if (myDiagramType == 4 )
        {width = 15; height = 15;}
        else if (myDiagramType > 4 )
        {width = 10; height = 10;}

	if (myDiagramType == protein || myDiagramType == domain )
	{
		myText = "Entity";
		QPainterPath path;
		QRectF rect = outlineRect();
                width = int(rect.width()); height = int(rect.height());
		path.addRoundRect(rect, roundness(rect.width()),
                      roundness(rect.height()));
		myPolygon = path.toFillPolygon();
		

	}
	else if (myDiagramType == DNA )
	{
		myText= "Entity";
		QPainterPath path;
		QRectF rect = outlineRect();
                width = int(rect.width()); height = int(rect.height());
		path.addRect(rect);
		myPolygon = path.toFillPolygon();

	}
	else if (myDiagramType == Small )
	{
		myText= "P";
		QPainterPath path;
		QRectF rect = outlineRect();
		//width = rect.width(); height = rect.height();
		path.addRoundRect(rect, roundness(rect.width()),
                      roundness(rect.height()));
		myPolygon = path.toFillPolygon();

	}
	else if (myDiagramType == sourceSink )
	{
		myText= "";
		QPainterPath path;
		QRectF rect = outlineRect();
		//width = rect.width(); height = rect.height();
		path.addRoundRect(rect, roundness(rect.width()),
                      roundness(rect.height()));
		path.addEllipse(rect.center(), 8.0 , 8.0);
		path.moveTo(rect.bottomLeft());
		path.lineTo(rect.topRight());
		myPolygon = path.toFillPolygon();

	}
	else if ( myDiagramType == Complex || myDiagramType == Dot )
	{
		myText==  "";
		QPainterPath path;
		QRectF rect = outlineRect();
		//width = rect.width(); height = rect.height();
		path.addRoundRect(rect, roundness(rect.width()),
                      roundness(rect.height()));
		path.addEllipse(rect.center(), 5.0 , 5.0);
		myPolygon = path.toFillPolygon();
		per = 0.5;
	}
	else if ( myDiagramType == Trans)
	{
		myText==  "";
		QPainterPath path;
		QRectF rect = outlineRect();
                width = int(rect.width()); height = int(rect.height());
		path.addRoundRect(rect, roundness(rect.width()),
                      roundness(rect.height()));
		QPointF middle = rect.center();
		path.moveTo(QPointF(middle.x(), middle.y()-5));
		path.lineTo(QPointF(middle.x()-10, middle.y()+5));
		path.moveTo(QPointF(middle.x(), middle.y()+5));
		path.lineTo(QPointF(middle.x()+10, middle.y()-5));
		myPolygon = path.toFillPolygon();
		per = 0.5;
	}
	else if ( myDiagramType == Invisible)
	{
		myText==  "";
		QPainterPath path;
		QRectF rect = outlineRect();
		setPen(QPen(QColor(Qt::transparent)));
		//width = rect.width(); height = rect.height();
		path.addRoundRect(rect, roundness(rect.width()),
                      roundness(rect.height()));
		path.addEllipse(rect.center(), 5 , 5);
		myPolygon = path.toFillPolygon();
		per = 0.5;
	}

	setFlags(ItemIsMovable | ItemIsSelectable | ItemSendsGeometryChanges);
	setPolygon(myPolygon);
	
	
 }

 void DiagramItem::addEdge(Edge *arrow)
 {
     edges.push_back(arrow);
 }

QRectF DiagramItem::outlineRect() const
{


    const int Padding = 8;
    QFontMetricsF metrics = qApp->font();
	QRectF rect;
	if ( myDiagramType < 4 )
		rect = metrics.boundingRect(myText);
	else 
		rect = metrics.boundingRect("");
    rect.adjust(-Padding, -Padding, +Padding, +Padding);
    //rect.translate(-rect.center());
        if ( width > 29 && height > 29 )
        {
		rect.setWidth(width);
		rect.setHeight(height);
        }

    return rect;
}
int DiagramItem::roundness(double size) const
{
    const int Diameter = 12;
    return 100 * Diameter / int(size);
}
void DiagramItem::setText(const QString &text)
{
    //prepareGeometryChange();
    myText = text;
    update();
}
void DiagramItem::setWidthHeight(const int &w, const int & h)
{
    prepareGeometryChange();
    qreal ratio1 = w/width;
    qreal ratio2 = h/height;
    width = w;
    height = h;
    QRectF rect = outlineRect();
    sizeChange(ratio1, ratio2);
    update();
}

QString DiagramItem::text()  const
{
	return myText;
}

QRectF DiagramItem::boundingRect() const
{
		//return QRectF(rect.left()-27, rect.topLeft().y(), rect.width()+54, rect.height()+4);
		return QRectF(outlineRect().topLeft().x()- 60,outlineRect().topLeft().y(), outlineRect().width()+120 , outlineRect().height()); 
}
void DiagramItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
	QString text;
	if ( myDiagramType != Trans && myDiagramType != sourceSink && myDiagramType != Invisible)
	{
            text = QInputDialog::getText(event->widget(),"Edit Text", "Enter new text:",QLineEdit::Normal, myText);
            if ( text!= "")
                setText(text);
	}
}

void DiagramItem::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{

		QGraphicsItem::mousePressEvent(mouseEvent);
	
}
void DiagramItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if ((myDiagramType >5 ) && !host->points.empty() )
{
	QPainterPath p(host->points.first());
	int k = 0;

	for ( int i = 0 ; i < host->points.size()-1 ; i++)
	{
		int min1 = min(int(host->points.at(i).y()), int(host->points.at(i+1).y()));
		int min2 = max(int(host->points.at(i).y()), int(host->points.at(i+1).y()));
		bool b1 = host->points.at(i).x() == host->points.at(i+1).x();
		bool b2 = pos().x() <= host->points.at(i).x()+0.05;
		bool b5 = host->points.at(i).x()-0.05 <= pos().x();
		bool b3 = min1 <= int(pos().y());
		bool b4 = int(pos().y()) <= min2;
		if ( (b1) 
			&&  (b2)
			&& (b3 ) 
			&&  ( b4) && b5 )
		{
			setPos(x(), mouseEvent->scenePos().y());
			k = i;
			if  (host->points.at(i).y() <  host->points.at(i+1).y() )
			{
				if ( mouseEvent->scenePos().y() > host->points.at(i+1).y() )//&& !(i+2 != pa.size()-1 && pa.at(i+1).x() == pa.at(i+2).x()) ) 
					setPos(host->points.at(i+1));
				else if ( mouseEvent->scenePos().y() < host->points.at(i).y() )//&& !(i-1 != -1 && pa.at(i-1).x() == pa.at(i).x())  )
					setPos(host->points.at(i)); 
			}
			if ( host->points.at(i).y() >  host->points.at(i+1).y() )
                        {
				if ( mouseEvent->scenePos().y() < host->points.at(i+1).y() )
					setPos(host->points.at(i+1));
				else if ( mouseEvent->scenePos().y() > host->points.at(i).y() )
					setPos(host->points.at(i)); 
			}			
		}
		else if( (host->points.at(i).y() == host->points.at(i+1).y()) 
			&&  (pos().y() <= host->points.at(i).y() + 0.05) 
			&&  ( host->points.at(i).y() - 0.05 <= pos().y() )
			&& (min(int(host->points.at(i).x()), int(host->points.at(i+1).x())) <= int(pos().x())) 
			&& (int(pos().x()) <= max(int(host->points.at(i).x()), int(host->points.at(i+1).x()))) )
		{
			setPos(mouseEvent->scenePos().x(), y());
			k = i;
			if ( host->points.at(i).x() <  host->points.at(i+1).x() )
			{
				if (  mouseEvent->scenePos().x() < host->points.at(i).x() )
					setPos(host->points.at(i));
				if (  mouseEvent->scenePos().x() > host->points.at(i+1).x() )
					setPos(host->points.at(i+1));
			}
			else if (  host->points.at(i).x() > host->points.at(i+1).x()  )
			{
				if (  mouseEvent->scenePos().x() > host->points.at(i).x() )
					setPos(host->points.at(i));
				if (  mouseEvent->scenePos().x() < host->points.at(i+1).x() )
					setPos(host->points.at(i+1));
			}
		}		
	}
	for ( int j = 0; j < k; j++)
		p.lineTo(host->points.at(j+1));
	p.lineTo(pos());
	per = host->path().percentAtLength(p.length());
} else
	QGraphicsItem::mouseMoveEvent(mouseEvent);

}
void DiagramItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
	QGraphicsItem::mouseReleaseEvent(mouseEvent);
}

void DiagramItem::paint(QPainter *painter,
                 const QStyleOptionGraphicsItem *option,
                 QWidget * )
{
	QPen pen(Qt::black);

	if (option->state & QStyle::State_Selected) 
	{
		pen.setStyle(Qt::DotLine);
		pen.setWidth(2);
	}
	painter->setPen(pen);
 
	if ( myDiagramType == Complex || myDiagramType == Dot)
	{
		painter->setBrush(Qt::black);
		QRectF rect = outlineRect();
		painter->drawEllipse(rect.center(), 5.0 , 5.0);
		//painter->drawRect(outlineRect());
		setPolygon(QPolygonF(rect));

	} else if ( myDiagramType == Trans)
	{
		painter->setBrush(Qt::black);
		QRectF rect = outlineRect();
		painter->drawLine(QPointF(rect.center().x(), rect.center().y()-5),QPointF(rect.center().x()-10, rect.center().y()+5) );
		painter->drawLine(QPointF(rect.center().x(), rect.center().y()+5),QPointF(rect.center().x()+10, rect.center().y()-5) );

	} else if ( myDiagramType == sourceSink)
	{
		painter->setBrush(Qt::NoBrush);
		QRectF rect = outlineRect();
		painter->drawEllipse(rect.center(), 8.0 , 8.0 );
		painter->drawLine(rect.bottomLeft(), rect.topRight());

	}else if ( myDiagramType == Invisible)
	{
		painter->setBrush(Qt::NoBrush);
		painter->setPen(QColor(Qt::transparent));
		QRectF rect = outlineRect();
		painter->drawEllipse(rect.center(), 5.0 , 5.0);
		setPolygon(QPolygonF(rect));
	}
	else
	{
		painter->setBrush(Qt::white);
		QRectF rect = outlineRect();
		if (myDiagramType == 0 || myDiagramType == 1)
		{
			painter->drawRoundRect(rect, roundness(rect.width()), roundness(rect.height()));
			setPolygon(QPolygonF(rect));
        }else if (myDiagramType == 3  )
		{
			painter->drawRect(rect);
			painter->setPen(QPen(Qt::black, 8));
			prepareGeometryChange();
			setPolygon(QPolygonF(rect));
        }else if (myDiagramType == 2)
		{
			if (!(option->state & QStyle::State_Selected)) 
				painter->setPen(QPen(Qt::white,1));
			painter->drawRoundRect(rect);
			setPolygon(QPolygonF(rect));
		}

		painter->setPen(QPen(Qt::black, 5));
		if ( myDiagramType < 4)
			painter->drawText(rect, Qt::AlignCenter, myText);
	}
}
QVariant DiagramItem::itemChange(GraphicsItemChange change, // bu ise yaram?yor.
                          const QVariant &value)
{
    if (change == ItemPositionHasChanged ) 
	{

		foreach (Edge* edge, edges) 
			edge->change();
    }

    return QGraphicsItem::itemChange(change, value);
}
QPainterPath DiagramItem::shape() const
 {
	 QPainterPath path;
		path.addRect(outlineRect());
	 return path;
 }

void DiagramItem::sizeChange(const qreal &r1, const qreal &r2)
{
		QPointF py, px;
		foreach (Edge* edge, edges)
		{
				if( edge->startItem() == this)
				{
                                    edge->startx = edge->startx*r1;
                                    edge->starty = edge->starty*r2;
                                    if (edge->startUp)
                                        edge->points.value(edge->points.size()-2).setX(edge->startx);
                                    else
                                        edge->points.value(edge->points.size()-2).setY(edge->starty);
                                    edge->points.last() = QPointF(edge->startx, edge->starty);
                                        //py = edge->intersectStartItem();

				} else if (edge->endItem() == this)
				{
                                        //px = edge->intersect();
                                        edge->endx = edge->endx*r1;
                                        edge->endy = edge->endy*r2;
                                        if (edge->endUp)
                                            edge->points.value(edge->points.size()-2).setX(edge->endx);
                                        else
                                            edge->points.value(edge->points.size()-2).setY(edge->endy);
                                        edge->points.last() = QPointF(edge->startx, edge->endy);
				}
				edge->trackDiagramItem();
		
			
		}
}
QString DiagramItem::returnEnum(const int &num)
{
	if ( num == 0 )
            return "SimplePhysicalEntity";
	else if ( num == 1)
                return "EntityFeature";
	else if ( num == 2)
                return "Modifier";
	else if ( num == 3)
                return "ConceptualEntity";
	else if ( num == 4)
                return "SourceSink";
	else if ( num == 5)
                return "RestrictedCopy";
	else if ( num == 6)
                return "ExplicitComplex";
	else if ( num == 7)
                return "InTrans";
	else if ( num == 8)
                return "Invisible";

        return "InteractionGlyph";
}


